In the last article we learnt about Color Spaces and Conversion. In this article, we are going to learn how to apply Arithmetic and Bitwise Operations on Image in Python using OpenCV library.
First, let鈥檚 go through the arithmetic operations.
Arithmetic OperationsAdditionThis is the very basic and first topic of Arithmetic Operations on Image. The cv2.add() function is used to add two images or add a scalar to an image. It takes two images as arguments, or one image and a scalar value. Note that to add two images, both need to be of the same size.
You can add two images using the NumPy addition as well, i.e., result = img1 + img2. However, the results of the OpenCV function are much better.
We are going to add a football image to a football ground, as shown below.
football.jpgground.jpgBut before adding them, we need to resize them to the same size. For that, we will use the cv2.resize() function. It takes the image that needs to be resized and the tuple containing the width and the height, i.e., (width, height). Let鈥檚 see.
import cv2img1 = cv2.imread("ground.jpg")img2 = cv2.imread("football.jpg")img1 = cv2.resize(img1, (500, 400))img2 = cv2.resize(img2, (500, 400))cv2.imshow("Ground", img1)cv2.imshow("Football", img2)cv2.waitKey(0)cv2.destroyAllWindows()Output
Both images have dimensions (400, 500, 3).
Now, let鈥檚 add them.
import cv2img1 = cv2.imread("ground.jpg")img2 = cv2.imread("football.jpg")img1 = cv2.resize(img1, (500, 400))img2 = cv2.resize(img2, (500, 400))result_opencv = cv2.add(img1, img2)result_numpy = img1 + img2cv2.imshow("Result OpenCv", result_opencv)cv2.imshow("Result Numpy", result_numpy)cv2.waitKey(0)cv2.destroyAllWindows()Output
As you can see in the output, the result using the OpenCV function is a lot better than the manual addition. But the result is still not satisfactory. Most of the time, we do not want to add the exact values of both images. In other words, we want to have the effect of one image more than the other, i.e., add some transparency to images. Fortunately, OpenCV provides a function to do that. The cv2.addWeighted() function allows us to add weights to images. i.e.,
result = w1 脳 img1 + w2 脳 img2 + c
Where w1 is the weight applied to the img1, w2 is the weight applied to the img2, and c is a scalar value to increase (when c is positive) or decrease (when c is negative) brightness.
The function takes 5 arguments according to the above equation, i.e., cv2.addWeighted(img1, w1, img2, w2, c).
Let鈥檚 try to improve the above result using this function.
import cv2img1 = cv2.imread("ground.jpg")img2 = cv2.imread("football.jpg")img1 = cv2.resize(img1, (500, 400))img2 = cv2.resize(img2, (500, 400))result= cv2.addWeighted(img1, 0.5, img2, 0.5, 0)cv2.imshow("Result OpenCv", result)cv2.waitKey(0)cv2.destroyAllWindows()Output
As you can see, it has improved a lot.
SubtractionThe cv2.subtract() function is used to subtract one image from another or a scalar value from an image. Like, cv2.add(), both need to be of the same size.
Image subtraction is usually used to compare two images, i.e., highlight differences between two images.
Use the cv2.subtract() method instead of the manual subtraction, i.e., img1-img2, because it provides better results.
Let鈥檚 find the difference between the following two images.
dog1.jpgdog2.jpgimport cv2img1 = cv2.imread("dog1.jpg")img2 = cv2.imread("dog2.jpg")img1 = cv2.resize(img1, (500, 400))img2 = cv2.resize(img2, (500, 400))result= cv2.subtract(img1, img2)cv2.imshow("Result", result)cv2.waitKey(0)cv2.destroyAllWindows()Output
In the above example, first, we read the above two images. Then, we resize them to the same size, i.e., (400, 500, 3). After that, we subtract img2 from img1 and display the result.
We have discussed the first part of the Arithmetic and Bitwise Operations on Image. Now we will discuss Bitwise operation.
Bitwise OperationsBefore performing the bitwise operations, first, let鈥檚 create two binary images. We will apply bitwise operations on them. Consider the code below.
import cv2import numpy as npimg1 = np.zeros((400, 400, 3), dtype = np.uint8)img2 = np.zeros((400, 400, 3), dtype = np.uint8)img1 = cv2.rectangle(img1, (150, 150), (250, 250), (255,255, 255), -1)img2 = cv2.rectangle(img2, (0, 200), (400, 400), (255,255, 255), -1)cv2.imshow("img1", img1)cv2.imshow("img2", img2)cv2.waitKey(0)cv2.destroyAllWindows()In the above example, first, we import numpy as np. Then, we use the np.zeros() function to create two images with dimensions (400, 400, 3). All the pixels in them are black, i.e., zero. Then, we use the cv2.rectangle() method to create a white region in them. It takes the image, (x, y) coordinates of the top left and bottom right rectangle, color, and thickness. In our case, the color is white, and the thickness is -1 because we want to fill the region with the white color. The resulting images are shown below.
Let鈥檚 now perform the bitwise AND, OR, XOR, and NOT operations on these images. The bitwise operators work similarly as the logical operators do. Let鈥檚 see each of them.
Bitwise AND OperationIn the AND operation, the resulting pixel is white (or 1 in the truth table given below) when the corresponding pixels in both the images are white. Otherwise, the resulting pixel has the black (0 in the truth table) color. The cv2.bitwise_and() function is used to perform the AND operation. Consider the table below to see how the AND operation works. Note that for images, 0 is black, and 1 is white.
ABAND000010100111import cv2import numpy as npimg1 = np.zeros((400, 400, 3), dtype = np.uint8)img2 = np.zeros((400, 400, 3), dtype = np.uint8)img1 = cv2.rectangle(img1, (150, 150), (250, 250), (255,255, 255), -1)img2 = cv2.rectangle(img2, (0, 200), (400, 400), (255,255, 255), -1)bit_and = cv2.bitwise_and(img1,img2)cv2.imshow("Bitwise AND", bit_and)cv2.waitKey(0)cv2.destroyAllWindows()Output
Bitwise OR OperationIn the OR operation, the resulting pixel has the black color (here, 0 in the truth table) when the corresponding pixels in both images are black. Otherwise, it is white (1 in the truth table). The cv2.bitwise_or() function is used for this.
ABOR000011101111import cv2import numpy as npimg1 = np.zeros((400, 400, 3), dtype = np.uint8)img2 = np.zeros((400, 400, 3), dtype = np.uint8)img1 = cv2.rectangle(img1, (150, 150), (250, 250), (255,255, 255), -1)img2 = cv2.rectangle(img2, (0, 200), (400, 400), (255,255, 255), -1)bit_or = cv2.bitwise_or(img1,img2)cv2.imshow("Bitwise OR", bit_or)cv2.waitKey(0)cv2.destroyAllWindows()Output
Bitwise XOR OperationThe cv2.bitwise_xor() function performs the XOR operation. It returns False when both the images have the same values, i.e., both are black, or both are white.
ABXOR000011101110import cv2import numpy as npimg1 = np.zeros((400, 400, 3), dtype = np.uint8)img2 = np.zeros((400, 400, 3), dtype = np.uint8)img1 = cv2.rectangle(img1, (150, 150), (250, 250), (255,255, 255), -1)img2 = cv2.rectangle(img2, (0, 200), (400, 400), (255,255, 255), -1)bit_xor = cv2.bitwise_xor(img1,img2)cv2.imshow("Bitwise XOR", bit_xor)cv2.waitKey(0)cv2.destroyAllWindows()Output
Bitwise NOT OperationThe NOT operation is quite straightforward. It just inverts the pixel value. If it is black (here, 0 in the truth table), the corresponding pixel in the resulting image will be white (1 in the truth table). The cv2.bitwise_not() performs the NOT operation.
ANOT0110import cv2import numpy as npimg1 = np.zeros((400, 400, 3), dtype = np.uint8)img2 = np.zeros((400, 400, 3), dtype = np.uint8)img1 = cv2.rectangle(img1, (150, 150), (250, 250), (255,255, 255), -1)img2 = cv2.rectangle(img2, (0, 200), (400, 400), (255,255, 255), -1)cv2.imshow("img1", img1)cv2.imshow("img2", img2)bit_not_img1 = cv2.bitwise_not(img1)bit_not_img2 = cv2.bitwise_not(img2)cv2.imshow("Bitwise NOT on img1", bit_not_img1)cv2.imshow("Bitwise NOT on img2", bit_not_img2)cv2.waitKey(0)cv2.destroyAllWindows()Output
MaskingPerforming bitwise operations on images has many applications. For example, we can manipulate it and extract its desired part. Moreover, the bitwise AND operation can be used in image masking. Image masking allows us to focus on a specific region in an image. It can be done using the bitwise AND operation. Let鈥檚 extract the football from the above football.jpg image.
import cv2import numpy as npimport matplotlib.pyplot as pltimg1 = cv2.imread("football.jpg")img1 = cv2.resize(img1, (500, 400))mask = np.zeros(img1.shape, dtype = img1.dtype)mask = cv2.rectangle(mask, (243, 190), (323, 275), (255,255, 255), -1)result = cv2.bitwise_and(img1,mask)cv2.imshow("Result", result)cv2.waitKey(0)cv2.destroyAllWindows()In the example above, we import NumPy to create a mask image using the np.zeros() function. It contains the same dimensions and the type as the img1, and all values are equal to zero. To get the desired region in the img1 (football), we need to make that region white in the mask image. For that, we use the cv2.rectangle() method. It is shown below.
Now that we have the mask image, let鈥檚 apply the bitwise AND operation between the img1 and the mask. The cv2.bitwise_and() chooses the smaller value from the given two values when performing the AND operation in a non-binary image. Therefore, all the pixels, excluding those in the football region, will become zero in the resulting image because the corresponding values in the mask image are zero. Moreover, in the football region, cv2.bitwise_and() will take values of the img1 because the mask image contains 255 (the maximum pixel value) everywhere in that region. Therefore, values in the img1 will either be smaller or equal to 255. The final result is shown below.
That’s all about Arithmetic and Bitwise Operations on Image. Cool, right?